home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Music / EDIT / AmiSOX3.3 / dist / sox.c < prev    next >
C/C++ Source or Header  |  1995-08-23  |  18KB  |  766 lines

  1. /*
  2.  * July 5, 1991
  3.  * Copyright 1991 Lance Norskog And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Lance Norskog And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. #include "st.h"
  11. #if    defined(unix) || defined(AMIGA) || defined(__OS2__)
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #endif
  15. #ifdef    __STDC__
  16. #include <stdarg.h>
  17. #else
  18. #include <varargs.h>
  19. #endif
  20. #include <ctype.h>
  21. #include <string.h>
  22. #ifdef VMS
  23. #include <errno.h>
  24. #include <perror.h>
  25. #define LASTCHAR        ']'
  26. #else
  27. #include <errno.h>
  28. #define LASTCHAR        '/'
  29. #endif
  30. /* YOU MAY WANT THIS
  31. #include <getopt.h>
  32. */
  33.  
  34. /*
  35.  * SOX main program.
  36.  *
  37.  * Rewrite for new nicer option syntax.  July 13, 1991.
  38.  * Rewrite for separate effects library.  Sep. 15, 1991.
  39.  */
  40.  
  41. #ifdef AMIGA
  42. /* This is the Amiga version string */
  43. #include "amiver.h"
  44. char *AmiVersion = AMIVERSION;
  45. #endif /* AMIGA */
  46.  
  47.  
  48. EXPORT float volume = 1.0;    /* expansion coefficient */
  49. int dovolume = 0;
  50. int clipped = 0;    /* Volume change clipping errors */
  51.  
  52. EXPORT float amplitude = 1.0;    /* Largest sample so far */
  53.  
  54. EXPORT int writing = 0;    /* are we writing to a file? */
  55.  
  56. /* export flags */
  57. EXPORT int verbose = 0;    /* be noisy on stderr */
  58. EXPORT int summary = 0;    /* just print summary of information */
  59.  
  60. long ibuf[BUFSIZ];    /* Intermediate processing buffer */
  61. long obuf[BUFSIZ];    /* Intermediate processing buffer */
  62.  
  63.  
  64. long volumechange();
  65.  
  66. #ifdef    DOS
  67. char writebuf[BUFSIZ];    /* output write buffer */
  68. #endif
  69.  
  70. void    gettype(), geteffect(), checkeffect();
  71.  
  72. EXPORT struct soundstream informat, outformat;
  73.  
  74. char *myname;
  75.  
  76. ft_t ft;
  77. struct effect eff;
  78. char *ifile, *ofile, *itype, *otype;
  79. IMPORT char *optarg;
  80. IMPORT int optind;
  81.  
  82. main(n, args)
  83. int n;
  84. char **args;
  85. {
  86.     myname = args[0];
  87.     init();
  88.     
  89.     ifile = ofile = NULL;
  90.  
  91.     /* Get input format options */
  92.     ft = &informat;
  93.     doopts(n, args);
  94.     /* Get input file */
  95.     if (optind >= n)
  96. #ifndef    VMS
  97.         usage("No input file?");
  98. #else
  99.         /* I think this is the VMS patch, but am not certain */
  100.         fail("Input file required");    
  101. #endif
  102.     ifile = args[optind];
  103.     if (! strcmp(ifile, "-"))
  104.         ft->fp = stdin;
  105.     else if ((ft->fp = fopen(ifile, READBINARY)) == NULL)
  106.         fail("Can't open input file '%s': %s", 
  107.             ifile, strerror(errno));
  108.     ft->filename = ifile;
  109.     optind++;
  110.  
  111.     /* Let -e allow no output file, just do an effect */
  112.     if (optind < n) {
  113.         if (strcmp(args[optind], "-e")) {
  114.         /* Get output format options */
  115.         ft = &outformat;
  116.         doopts(n, args);
  117.         /* Get output file */
  118.         if (optind >= n)
  119.             usage("No output file?");
  120.         ofile = args[optind];
  121.         ft->filename = ofile;
  122.         /*
  123.          * There are two choices here:
  124.          *    1) stomp the old file - normal shell "> file" behavior
  125.          *    2) fail if the old file already exists - csh mode
  126.          */
  127.         if (! strcmp(ofile, "-"))
  128.             ft->fp = stdout;
  129.         else {
  130. #ifdef    unix
  131.              /*    
  132.              * Remove old file if it's a text file, but 
  133.               * preserve Unix /dev/sound files.  I'm not sure
  134.              * this needs to be here, but it's not hurting
  135.              * anything.
  136.              */
  137.             if ((ft->fp = fopen(ofile, WRITEBINARY)) && 
  138.                    (filetype(fileno(ft->fp)) == S_IFREG)) {
  139.                 fclose(ft->fp);
  140.                 unlink(ofile);
  141.                 creat(ofile, 0666);
  142.                 ft->fp = fopen(ofile, WRITEBINARY);
  143.             }
  144. #else
  145.             ft->fp = fopen(ofile, WRITEBINARY);
  146. #endif
  147.             if (ft->fp == NULL)
  148.                 fail("Can't open output file '%s': %s", 
  149.                     ofile, strerror(errno));
  150. #ifdef    DOS
  151.             if (setvbuf (ft->fp,writebuf,_IOFBF,sizeof(writebuf)))
  152.                 fail("Can't set write buffer");
  153. #endif
  154.         }
  155.         writing = 1;
  156.         }
  157.         optind++;
  158.     }
  159.  
  160.     /* ??? */
  161. /*
  162.     if ((optind < n) && !writing && !eff.name)
  163.         fail("Can't do an effect without an output file!");
  164. */
  165.  
  166.     /* Get effect name */
  167.     if (optind < n) {
  168.         eff.name = args[optind];
  169.         optind++;
  170.         geteffect(&eff);
  171.         (* eff.h->getopts)(&eff, n - optind, &args[optind]);
  172.     }
  173.  
  174.     /* 
  175.      * If we haven't specifically set an output file 
  176.      * don't write a file; we could be doing a summary
  177.      * or a format check.
  178.      */
  179. /*
  180.     if (! ofile)
  181.         usage("Must be given an output file name");
  182. */
  183.     if (! ofile)
  184.         writing = 0;
  185.     /* Check global arguments */
  186.     if (volume <= 0.0)
  187.         fail("Volume must be greater than 0.0");
  188. #if    defined(unix) || defined(AMIGA)
  189.     informat.seekable  = (filetype(fileno(informat.fp)) == S_IFREG);
  190.     outformat.seekable = (filetype(fileno(outformat.fp)) == S_IFREG); 
  191. #else
  192. #if    defined(DOS) || defined(__OS2__)
  193.     informat.seekable  = 1;
  194.     outformat.seekable = 1;
  195. #else
  196.     informat.seekable  = 0;
  197.     outformat.seekable = 0;
  198. #endif
  199. #endif
  200.  
  201.     /* If file types have not been set with -t, set from file names. */
  202.     if (! informat.filetype) {
  203.         if (informat.filetype = strrchr(ifile, LASTCHAR))
  204.             informat.filetype++;
  205.         else
  206.             informat.filetype = ifile;
  207.         if (informat.filetype = strrchr(informat.filetype, '.'))
  208.             informat.filetype++;
  209.         else /* Default to "auto" */
  210.             informat.filetype = "auto";
  211.     }
  212.     if (writing && ! outformat.filetype) {
  213.         if (outformat.filetype = strrchr(ofile, LASTCHAR))
  214.             outformat.filetype++;
  215.         else
  216.             outformat.filetype = ofile;
  217.         if (outformat.filetype = strrchr(outformat.filetype, '.'))
  218.             outformat.filetype++;
  219.     }
  220.     /* Default the input comment to the filename. 
  221.      * The output comment will be assigned when the informat 
  222.      * structure is copied to the outformat. 
  223.      */
  224.     informat.comment = informat.filename;
  225.  
  226.     process();
  227.     statistics();
  228.     exit(0);
  229. }
  230.  
  231. doopts(n, args)
  232. int n;
  233. char **args;
  234. {
  235.     int c;
  236.     char *str;
  237.  
  238.     while ((c = getopt(n, args, "r:v:t:c:suUAbwlfdDxSV")) != -1) {
  239.         switch(c) {
  240.         case 't':
  241.             if (! ft) usage("-t");
  242.             ft->filetype = optarg;
  243.             if (ft->filetype[0] == '.')
  244.                 ft->filetype++;
  245.             break;
  246.  
  247.         case 'r':
  248.             if (! ft) usage("-r");
  249.             str = optarg;
  250.             if ((! sscanf(str, "%lu", &ft->info.rate)) ||
  251.                     (ft->info.rate <= 0))
  252.                 fail("-r must be given a positive integer");
  253.             break;
  254.         case 'v':
  255.             if (! ft) usage("-v");
  256.             str = optarg;
  257.             if ((! sscanf(str, "%e", &volume)) ||
  258.                     (volume <= 0))
  259.                 fail("Volume value '%s' is not a number",
  260.                     optarg);
  261.             dovolume = 1;
  262.             break;
  263.  
  264.         case 'c':
  265.             if (! ft) usage("-c");
  266.             str = optarg;
  267.             if (! sscanf(str, "%d", &ft->info.channels))
  268.                 fail("-c must be given a number");
  269.             break;
  270.         case 'b':
  271.             if (! ft) usage("-b");
  272.             ft->info.size = BYTE;
  273.             break;
  274.         case 'w':
  275.             if (! ft) usage("-w");
  276.             ft->info.size = WORD;
  277.             break;
  278.         case 'l':
  279.             if (! ft) usage("-l");
  280.             ft->info.size = LONG;
  281.             break;
  282.         case 'f':
  283.             if (! ft) usage("-f");
  284.             ft->info.size = FLOAT;
  285.             break;
  286.         case 'd':
  287.             if (! ft) usage("-d");
  288.             ft->info.size = DOUBLE;
  289.             break;
  290.         case 'D':
  291.             if (! ft) usage("-D");
  292.             ft->info.size = IEEE;
  293.             break;
  294.  
  295.         case 's':
  296.             if (! ft) usage("-s");
  297.             ft->info.style = SIGN2;
  298.             break;
  299.         case 'u':
  300.             if (! ft) usage("-u");
  301.             ft->info.style = UNSIGNED;
  302.             break;
  303.         case 'U':
  304.             if (! ft) usage("-U");
  305.             ft->info.style = ULAW;
  306.             break;
  307.         case 'A':
  308.             if (! ft) usage("-A");
  309.             ft->info.style = ALAW;
  310.             break;
  311.         
  312.         case 'x':
  313.             if (! ft) usage("-x");
  314.             ft->swap = 1;
  315.             break;
  316.         
  317. /*  stat effect does this ?
  318.         case 'S':
  319.             summary = 1;
  320.             break;
  321. */
  322.         case 'V':
  323.             verbose = 1;
  324.             break;
  325.         }
  326.     }
  327. }
  328.  
  329. init() {
  330.  
  331.     /* init files */
  332.     informat.info.rate      = outformat.info.rate  = 0;
  333.     informat.info.size      = outformat.info.size  = -1;
  334.     informat.info.style     = outformat.info.style = -1;
  335.     informat.info.channels  = outformat.info.channels = -1;
  336.     informat.comment   = outformat.comment = NULL;
  337.     informat.swap      = 0;
  338.     informat.filetype  = outformat.filetype  = (char *) 0;
  339.     informat.fp        = stdin;
  340.     outformat.fp       = stdout;
  341.     informat.filename  = "input";
  342.     outformat.filename = "output";
  343. }
  344.  
  345. /* 
  346.  * Process input file -> effect -> output file
  347.  *    one buffer at a time
  348.  */
  349.  
  350. process() {
  351.     long isamp, osamp, istart;
  352.     long i, idone, odone;
  353.  
  354.     gettype(&informat);
  355.     if (writing)
  356.         gettype(&outformat);
  357.     /* Read and write starters can change their formats. */
  358.     (* informat.h->startread)(&informat);
  359.     checkformat(&informat);
  360.     report("Input file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  361.         informat.info.rate, sizes[informat.info.size], 
  362.         styles[informat.info.style], informat.info.channels, 
  363.         (informat.info.channels > 1) ? "channels" : "channel");
  364.     if (informat.comment)
  365.         report("Input file: comment \"%s\"\n",
  366.             informat.comment);
  367.     if (writing) {
  368.         copyformat(&informat, &outformat);
  369.         (* outformat.h->startwrite)(&outformat);
  370.         checkformat(&outformat);
  371.         cmpformats(&informat, &outformat);
  372.     report("Output file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  373.         outformat.info.rate, sizes[outformat.info.size], 
  374.         styles[outformat.info.style], outformat.info.channels, 
  375.         (outformat.info.channels > 1) ? "channels" : "channel");
  376.         if (outformat.comment)
  377.             report("Output file: comment \"%s\"\n",
  378.                 outformat.comment);
  379.     }
  380.     /* Very Important: 
  381.      * Effect fabrication and start is called AFTER files open.
  382.      * Effect may write out data beforehand, and
  383.      * some formats don't know their sample rate until now.
  384.      */
  385.     checkeffect(0);
  386.     /* inform effect about signal information */
  387.     eff.ininfo = informat.info;
  388.     eff.outinfo = outformat.info;
  389.     (* eff.h->start)(&eff);
  390.     istart = 0;
  391.     while((isamp = (*informat.h->read)(&informat,&ibuf[istart],
  392.             (long) BUFSIZ-istart))>0) {
  393.         long *ib = ibuf;
  394.  
  395.         isamp += istart;
  396.         /* Do volume before effect or after?  idunno */
  397.         if (dovolume) for (i = 0; i < isamp; i++)
  398.             ibuf[i] = volumechange(ibuf[i]);
  399.         osamp = sizeof(obuf) / sizeof(long);
  400.         /* Effect (i.e. rate change) may do different sizes I and O */
  401.         while (isamp) {
  402.             idone = isamp;
  403.             odone = osamp;
  404.             (* eff.h->flow)(&eff, ib, obuf, &idone, &odone);
  405.             /* 
  406.              * kludge!     
  407.              * Effect is stuck.  Start over with new buffer.
  408.              * This can drop samples at end of file. 
  409.              * No effects currently do this, but it could happen.
  410.              */
  411.             if (idone == 0) {
  412.                 int i;
  413.                 for(i = isamp - 1; i; i--)
  414.                     ibuf[i] = ib[i];
  415.                 istart = isamp;
  416.                 isamp = 0;
  417.                 break;
  418.             }
  419.             if (writing && (odone > 0)) 
  420.                 (* outformat.h->write)(&outformat, obuf, (long) odone);
  421.             isamp -= idone;
  422.             ib += idone;
  423.         }
  424.     }
  425.     /* Drain effect out */
  426.     if (writing) {
  427.         odone = sizeof(obuf) / sizeof(long);
  428.         (* eff.h->drain)(&eff, obuf, &odone);
  429.         if (odone > 0)
  430.             (* outformat.h->write)(&outformat, obuf, (long) odone);
  431.         /* keep calling it until it returns a partial buffer */
  432.         while (odone == (sizeof(obuf) / sizeof(long))) {
  433.             (* eff.h->drain)(&eff, obuf, &odone);
  434.             if (odone)
  435.              (* outformat.h->write)(&outformat, obuf, (long) odone);
  436.         }
  437.     }
  438.     /* Very Important: 
  439.      * Effect stop is called BEFORE files close.
  440.      * Effect may write out more data after. 
  441.      */
  442.     (* eff.h->stop)(&eff);
  443.     (* informat.h->stopread)(&informat);
  444.     fclose(informat.fp);
  445.     if (writing)
  446.         (* outformat.h->stopwrite)(&outformat);
  447.     if (writing)
  448.         fclose(outformat.fp);
  449. }
  450.  
  451. /*
  452.  * Check that we have a known format suffix string.
  453.  */
  454. void
  455. gettype(formp)
  456. ft_t formp;
  457. {
  458.     char **list;
  459.     int i;
  460.  
  461.     if (! formp->filetype)
  462. fail("Must give file type for %s file, either as suffix or with -t option",
  463. formp->filename);
  464.     for(i = 0; formats[i].names; i++) {
  465.         for(list = formats[i].names; *list; list++) {
  466.             char *s1 = *list, *s2 = formp->filetype;
  467.             if (! strcmpcase(s1, s2))
  468.                 break;    /* not a match */
  469.         }
  470.         if (! *list)
  471.             continue;
  472.         /* Found it! */
  473.         formp->h = &formats[i];
  474.         return;
  475.     }
  476.     if (! strcmpcase(formp->filetype, "snd")) {
  477.         verbose = 1;
  478.         report("File type '%s' is used to name several different formats.", formp->filetype);
  479.         report("If the file came from a Macintosh, it is probably");
  480.         report("a .ub file with a sample rate of 11025 (or possibly 5012 or 22050).");
  481.         report("Use the sequence '-t .ub -r 11025 file.snd'");
  482.         report("If it came from a PC, it's probably a Soundtool file.");
  483.         report("Use the sequence '-t .sndt file.snd'");
  484.         report("If it came from a NeXT, it's probably a .au file.");
  485.         fail("Use the sequence '-t .au file.snd'\n");
  486.     }
  487.     fail("File type '%s' of %s file is not known!",
  488.         formp->filetype, formp->filename);
  489. }
  490.  
  491. copyformat(ft, ft2)
  492. ft_t ft, ft2;
  493. {
  494.     int noise = 0;
  495.     if (ft2->info.rate == 0) {
  496.         ft2->info.rate = ft->info.rate;
  497.         noise = 1;
  498.     }
  499.     if (outformat.info.size == -1) {
  500.         ft2->info.size = ft->info.size;
  501.         noise = 1;
  502.     }
  503.     if (outformat.info.style == -1) {
  504.         ft2->info.style = ft->info.style;
  505.         noise = 1;
  506.     }
  507.     if (outformat.info.channels == -1) {
  508.         ft2->info.channels = ft->info.channels;
  509.         noise = 1;
  510.     }
  511.     if (outformat.comment == NULL) {
  512.         ft2->comment = ft->comment;
  513.         noise = 1;
  514.     }
  515.     return noise;
  516. }
  517.  
  518. cmpformats(ft, ft2)
  519. ft_t ft, ft2;
  520. {
  521.     int noise = 0;
  522.     float abs;
  523.  
  524. }
  525.  
  526. /* check that all settings have been given */
  527. checkformat(ft) 
  528. ft_t ft;
  529. {
  530.     if (ft->info.rate == 0)
  531.         fail("Sampling rate for %s file was not given\n", ft->filename);
  532.     if ((ft->info.rate < 100) || (ft->info.rate > 50000))
  533.         fail("Sampling rate %lu for %s file is bogus\n", 
  534.             ft->info.rate, ft->filename);
  535.     if (ft->info.size == -1)
  536.         fail("Data size was not given for %s file\nUse one of -b/-w/-l/-f/-d/-D", ft->filename);
  537.     if (ft->info.style == -1)
  538.         fail("Data style was not given for %s file\nUse one of -s/-u/-U/-A", ft->filename);
  539.     /* it's so common, might as well default */
  540.     if (ft->info.channels == -1)
  541.         ft->info.channels = 1;
  542.     /*    fail("Number of output channels was not given for %s file",
  543.             ft->filename); */
  544. }
  545.  
  546. /*
  547.  * If no effect given, decide what it should be.
  548.  */
  549. void
  550. checkeffect(effp)
  551. eff_t effp;
  552. {
  553.     int already = (eff.name != (char *) 0);
  554.     char *rate = 0, *chan = 0;
  555.     int i;
  556.  
  557.     for (i = 0; effects[i].name; i++) {
  558.         if (!chan && (effects[i].flags & EFF_CHAN))
  559.             chan = effects[i].name;
  560.         if (! rate && (effects[i].flags & EFF_RATE))
  561.             rate = effects[i].name;
  562.     }
  563.  
  564.     if (eff.name && ! writing)
  565.         return;
  566.  
  567.     /* 
  568.      * Require mixdown for channel mismatch.
  569.      * XXX Doesn't handle channel expansion.  Need an effect for this.
  570.      * Require one of the rate-changers on a rate change.
  571.      * Override a rate change by explicitly giving 'copy' command.
  572.      */
  573.     if (informat.info.channels != outformat.info.channels) {
  574.         if (eff.name && !(eff.h->flags & EFF_CHAN))
  575.             fail("Need to do change number of channels first.  Try the '%s' effect.", chan);
  576.         if (! eff.name) {
  577.             eff.name = chan;
  578.             report(
  579. "Changing %d input channels to %d output channels with '%s' effect\n",
  580.             informat.info.channels, outformat.info.channels, chan);
  581.             geteffect(&eff);
  582.         }
  583.     } 
  584.     /* 
  585.      * Be liberal on rate difference errors.
  586.      * Note that the SPARC 8000-8192 problem
  587.      * comes in just under the wire.  XXX
  588.      *
  589.       * Bogus.  Should just do a percentage.
  590.      */
  591.     if (abs(informat.info.rate - outformat.info.rate) > 200) {
  592.         if (eff.name && !(eff.h->flags & EFF_RATE))
  593.             fail("Need to do rate change first.  Try the '%s' effect.", 
  594.             rate);
  595.         if (! eff.name) {
  596.             eff.name = rate;
  597.             report(
  598. "Changing sample rate %lu to rate %lu via noisy 'rate' effect\n",
  599.             informat.info.rate, outformat.info.rate);
  600.             geteffect(&eff);
  601.         }
  602.     }
  603.     /* don't need to change anything */
  604.     if (! eff.name)
  605.         eff.name = "copy";
  606.     if (! already) {
  607.         geteffect(&eff);
  608.         /* give default opts for manufactured effect */
  609.         (* eff.h->getopts)(&eff, 0, (char *) 0);
  610.     }
  611. }
  612.  
  613. /*
  614.  * Check that we have a known effect name.
  615.  */
  616. void
  617. geteffect(effp)
  618. eff_t effp;
  619. {
  620.     int i;
  621.  
  622.     for(i = 0; effects[i].name; i++) {
  623.         char *s1 = effects[i].name, *s2 = effp->name;
  624.         while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  625.             s1++, s2++;
  626.         if (*s1 || *s2)
  627.             continue;    /* not a match */
  628.         /* Found it! */
  629.         effp->h = &effects[i];
  630.         return;
  631.     }
  632.     /* Guido Van Rossum fix */
  633.     fprintf(stderr, "Known effects:");
  634.     for (i = 0; effects[i].name; i++)
  635.         fprintf(stderr, "\t%s\n", effects[i].name);
  636.     fail("\nEffect '%s' is not known!", effp->name);
  637. }
  638.  
  639. /* Guido Van Rossum fix */
  640. statistics() {
  641.     if (dovolume && clipped > 0)
  642.         report("Volume change clipped %d samples", clipped);
  643. }
  644.  
  645. long volumechange(y)
  646. long y;
  647. {
  648.     double y1;
  649.  
  650.     y1 = y * volume;
  651.     if (y1 < -2147483647.0) {
  652.         y1 = -2147483647.0;
  653.         clipped++;
  654.     }
  655.     else if (y1 > 2147483647.0) {
  656.         y1 = 2147483647.0;
  657.         clipped++;
  658.     }
  659.  
  660.     return y1;
  661. }
  662.  
  663. #if    defined(unix) || defined(AMIGA)
  664. filetype(fd)
  665. int fd;
  666. {
  667.     struct stat st;
  668.  
  669.     fstat(fd, &st);
  670.  
  671.     return st.st_mode & S_IFMT;
  672. }
  673. #endif
  674.  
  675. char *usagestr = 
  676. "[ -V -S ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]\nfopts: -r rate -v volume -c channels -s/-u/-U/-A -b/-w/-l/-f/-d/-D -x\neffects and effopts: various";
  677.  
  678. usage(opt)
  679. char *opt;
  680. {
  681. #ifndef    DOS
  682.     /* single-threaded machines don't really need this */
  683.     fprintf(stderr, "%s: ", myname);
  684. #endif
  685.     fprintf(stderr, "Usage: %s", usagestr);
  686.     if (opt)
  687.         fprintf(stderr, "\nFailed at: %s\n", opt);
  688.     exit(1);
  689. }
  690.  
  691. void
  692. #ifdef    __STDC__
  693. report(char *fmt, ...)
  694. #else
  695. report(va_alist) 
  696. va_dcl
  697. #endif
  698. {
  699.     va_list args;
  700. #ifndef    __STDC__
  701.     char *fmt;
  702. #endif
  703.  
  704.     if (! verbose)
  705.         return;
  706. #ifndef    DOS
  707.     /* single-threaded machines don't really need this */
  708.     fprintf(stderr, "%s: ", myname);
  709. #endif
  710. #ifdef    __STDC__
  711.     va_start(args, fmt);
  712. #else
  713.     va_start(args);
  714.     fmt = va_arg(args, char *);
  715. #endif
  716.     vfprintf(stderr, fmt, args);
  717.     va_end(args);
  718.     fprintf(stderr, "\n");
  719. }
  720.  
  721. void
  722. #ifdef    __STDC__
  723. fail(char *fmt, ...)
  724. #else
  725. fail(va_alist) 
  726. va_dcl
  727. #endif
  728. {
  729.     va_list args;
  730. #ifndef    __STDC__
  731.     char *fmt;
  732. #endif
  733.  
  734. #ifndef    DOS
  735.     /* single-threaded machines don't really need this */
  736.     fprintf(stderr, "%s: ", myname);
  737. #endif
  738. #ifdef    __STDC__
  739.     va_start(args, fmt);
  740. #else
  741.     va_start(args);
  742.     fmt = va_arg(args, char *);
  743. #endif
  744.     vfprintf(stderr, fmt, args);
  745.     va_end(args);
  746.     fprintf(stderr, "\n");
  747.     /* Close the input file and outputfile before exiting*/
  748.     ft = &informat;
  749.     fclose(ft->fp);
  750.     ft = &outformat;
  751.     fclose(ft->fp);
  752.  
  753.     /* remove the output file because we failed */
  754.     REMOVE(ft->filename);
  755.     exit(2);
  756. }
  757.  
  758.  
  759. strcmpcase(s1, s2)
  760. char *s1, *s2;
  761. {
  762.     while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  763.         s1++, s2++;
  764.     return *s1 - *s2;
  765. }
  766.